﻿Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Reflection
Imports System.Globalization


''' <summary>
''' キー生成器
''' </summary>
''' <remarks>
''' インスタンスを一意の文字列に変換します
''' </remarks>
Public NotInheritable Class KeyGenerator

    Private Sub New()
    End Sub

    ''' <summary>
    ''' インスタンスキーを生成します
    ''' </summary>
    ''' <param name="instance"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' 書式：
    ''' ClassFullName(KeyPropertyNameN=KeyPropertyNameN=Value)
    ''' ClassFullName(KeyPropertyNameN=(ParentKeyPropertyNameN=Value))
    ''' </remarks>
    Public Shared Function Generate(instance As Object) As String
        If instance Is Nothing Then Return String.Empty

        ''コレクション型の場合はハッシュコードを返します
        'If TypeOf instance Is ICollection Then
        '    Dim s = String.Format("{0}(HashCode={1})", instance.GetType.Name, instance.GetHashCode.ToString)
        '    Return s
        'End If

        Dim t = instance.GetType
        Dim def = t.ToEntityDefinition
    
        Dim dic As New Dictionary(Of String, Object)
        For Each item In (From el In def.LiteralProperties Where el.IsKey)
            dic.Add(item.LiteralName, item.GetLiteralValue(instance))
        Next

        Dim key = KeyGenerator.Generate(t, dic)

        Return key
    End Function

    ''' <summary>
    ''' インスタンスキーを生成します
    ''' </summary>
    ''' <param name="instanceType"></param>
    ''' <param name="keys"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Generate(instanceType As Type, keys As Dictionary(Of String, Object)) As String
        If instanceType Is Nothing Then Throw New ArgumentNullException("instanceType")
        If keys Is Nothing Then Throw New ArgumentNullException("keys")

        Dim key As New StringBuilder
        For Each item In keys
            Dim val = item.Value
            If val Is Nothing OrElse String.IsNullOrEmpty(val.ToString) Then Return Nothing

            key.AppendDelimiter(",").AppendFormat("{0}={1}", item.Key, val.ToString)
        Next
        If key.Any = False Then Return Nothing

        Return String.Format("{0}({1})", instanceType.FullName, key.ToString)
    End Function
End Class
